// -----------------------------------------------------------------------
// <copyright file="AwsHttpClient.cs" company="Asynkron AB">
//      Copyright (C) 2015-2022 Asynkron AB All rights reserved
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace Proto.Cluster.AmazonECS;

[PublicAPI]
public class AwsEcsContainerMetadataHttpClient
{
    private readonly ILogger _logger = Log.CreateLogger<AwsEcsContainerMetadataHttpClient>();

    public ContainerMetadata GetContainerMetadata()
    {
        var str = Environment.GetEnvironmentVariable("ECS_CONTAINER_METADATA_URI_V4");
        try
        {
            if (Uri.TryCreate(str, UriKind.Absolute, out var containerMetadataUri))
            {
                var json = GetResponseString(containerMetadataUri);
                _logger.LogInformation("[AwsEcsContainerMetadataHttpClient] got metadata for container {Metadata}", json);
                return JsonConvert.DeserializeObject<ContainerMetadata>(json);
            }

            _logger.LogError("[AwsEcsContainerMetadataHttpClient] failed to get Metadata {Url}",str);

        }
        catch(Exception x)
        {
            _logger.LogError(x, "[AwsEcsContainerMetadataHttpClient] failed to get Metadata {Url}",str);
        }

        return null;
    }
        
    public TaskMetadata GetTaskMetadata()
    {
        var str = Environment.GetEnvironmentVariable("ECS_CONTAINER_METADATA_URI_V4") + "/task";
        try
        {
                
            if (Uri.TryCreate(str, UriKind.Absolute, out var containerMetadataUri))
            {
                var json = GetResponseString(containerMetadataUri);
                _logger.LogInformation("[AwsEcsContainerMetadataHttpClient] got metadata for task {Metadata}", json);
                return JsonConvert.DeserializeObject<TaskMetadata>(json);
            }

            _logger.LogError("[AwsEcsContainerMetadataHttpClient] failed to get Metadata {Url}", str);

        }
        catch(Exception x)
        {
            _logger.LogError(x, "[AwsEcsContainerMetadataHttpClient] failed to get Metadata {Url}", str);
        }

        return null;
    }
        
        
    //
    // public string GetHostPrivateIPv4Address() => GetResponseString(new Uri("http://169.254.169.254/latest/meta-data/local-ipv4"));
    //
    // public string GetHostPublicIPv4Address() => GetResponseString(new Uri("http://169.254.169.254/latest/meta-data/public-ipv4"));

    private string GetResponseString(Uri requestUri)
    {
        try
        {
            var request = WebRequest.Create(requestUri);

            using var response = (HttpWebResponse)request.GetResponse();

            if (response.StatusCode != HttpStatusCode.OK)
            {
                _logger.LogError("Failed to execute HTTP request. Request URI: {RequestUri}, Status code: {StatusCode}", requestUri, response.StatusCode);

                return default;
            }

            using var stream = response.GetResponseStream();
            using var reader = new StreamReader(stream!);

            return reader.ReadToEnd();
        }
        catch (WebException ex) when (ex.Status == WebExceptionStatus.UnknownError)
        {
            _logger.LogError(ex, "Network is unreachable");
            // Network is unreachable
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to get AWS metadata response");
        }

        return default;
    }
}
    
        

public class Limits
{
    [JsonProperty("CPU")]
    public int CPU { get; set; }
}

public class Network
{
    [JsonProperty("NetworkMode")]
    public string NetworkMode { get; set; }

    [JsonProperty("IPv4Addresses")]
    public List<string> IPv4Addresses { get; set; }

    [JsonProperty("AttachmentIndex")]
    public int AttachmentIndex { get; set; }

    [JsonProperty("MACAddress")]
    public string MACAddress { get; set; }

    [JsonProperty("IPv4SubnetCIDRBlock")]
    public string IPv4SubnetCIDRBlock { get; set; }

    [JsonProperty("DomainNameServers")]
    public List<string> DomainNameServers { get; set; }

    [JsonProperty("DomainNameSearchList")]
    public List<string> DomainNameSearchList { get; set; }

    [JsonProperty("PrivateDNSName")]
    public string PrivateDNSName { get; set; }

    [JsonProperty("SubnetGatewayIpv4Address")]
    public string SubnetGatewayIpv4Address { get; set; }
}

public class LogOptions
{
    [JsonProperty("awslogs-group")]
    public string AwslogsGroup { get; set; }

    [JsonProperty("awslogs-region")]
    public string AwslogsRegion { get; set; }

    [JsonProperty("awslogs-stream")]
    public string AwslogsStream { get; set; }
}

public class ContainerMetadata
{
    [JsonProperty("DockerId")]
    public string DockerId { get; set; }

    [JsonProperty("Name")]
    public string Name { get; set; }

    [JsonProperty("DockerName")]
    public string DockerName { get; set; }

    [JsonProperty("Image")]
    public string Image { get; set; }

    [JsonProperty("ImageID")]
    public string ImageID { get; set; }

    [JsonProperty("DesiredStatus")]
    public string DesiredStatus { get; set; }

    [JsonProperty("KnownStatus")]
    public string KnownStatus { get; set; }

    [JsonProperty("Limits")]
    public Limits Limits { get; set; }

    [JsonProperty("CreatedAt")]
    public string CreatedAt { get; set; }

    [JsonProperty("StartedAt")]
    public string StartedAt { get; set; }

    [JsonProperty("Type")]
    public string Type { get; set; }

    [JsonProperty("Networks")]
    public List<Network> Networks { get; set; }

    [JsonProperty("ContainerARN")]
    public string ContainerARN { get; set; }

    [JsonProperty("LogOptions")]
    public LogOptions LogOptions { get; set; }

    [JsonProperty("LogDriver")]
    public string LogDriver { get; set; }
}
    
public class Container
{
    [JsonProperty("DockerId")]
    public string DockerId { get; set; }

    [JsonProperty("Name")]
    public string Name { get; set; }

    [JsonProperty("DockerName")]
    public string DockerName { get; set; }

    [JsonProperty("Image")]
    public string Image { get; set; }

    [JsonProperty("ImageID")]
    public string ImageID { get; set; }

    [JsonProperty("DesiredStatus")]
    public string DesiredStatus { get; set; }

    [JsonProperty("KnownStatus")]
    public string KnownStatus { get; set; }

    [JsonProperty("Limits")]
    public Limits Limits { get; set; }

    [JsonProperty("CreatedAt")]
    public string CreatedAt { get; set; }

    [JsonProperty("StartedAt")]
    public string StartedAt { get; set; }

    [JsonProperty("Type")]
    public string Type { get; set; }

    [JsonProperty("Networks")]
    public List<Network> Networks { get; set; }

    [JsonProperty("LogDriver")]
    public string LogDriver { get; set; }

    [JsonProperty("LogOptions")]
    public LogOptions LogOptions { get; set; }

    [JsonProperty("ContainerARN")]
    public string ContainerARN { get; set; }
}

public class TaskMetadata
{
    [JsonProperty("Cluster")]
    public string Cluster { get; set; }

    [JsonProperty("TaskARN")]
    public string TaskARN { get; set; }

    [JsonProperty("Family")]
    public string Family { get; set; }

    [JsonProperty("Revision")]
    public string Revision { get; set; }

    [JsonProperty("DesiredStatus")]
    public string DesiredStatus { get; set; }

    [JsonProperty("KnownStatus")]
    public string KnownStatus { get; set; }

    [JsonProperty("PullStartedAt")]
    public string PullStartedAt { get; set; }

    [JsonProperty("PullStoppedAt")]
    public string PullStoppedAt { get; set; }

    [JsonProperty("AvailabilityZone")]
    public string AvailabilityZone { get; set; }

    [JsonProperty("LaunchType")]
    public string LaunchType { get; set; }

    [JsonProperty("Containers")]
    public List<Container> Containers { get; set; }
}